#include "bt_mutex.h"
#include <assert.h>

#include <time.h>

mutex_block::mutex_block(std::string n)
{
    
#ifdef WIN32
    ::InitializeCriticalSection(&m_mutex);
#endif
#ifdef LINUX
    pthread_mutex_init(&m_mutex, NULL);
#endif
    
    name = n;
    locks = 0;
    
#ifdef MUTEX_DEBUG_SIGNFILE
    MSNDEBUGSIGFILE((unsigned int )((void *)this), "create mutex_block %s \n", name.c_str());
#endif
    
#ifdef BTDEBUG
    MSNDEBUG(DEBUG_MUTEX, "create mutex_block %s\n", n.c_str());
#endif
}

mutex_block::~mutex_block()
{
    
#ifdef WIN32
    DeleteCriticalSection (&m_mutex);
#endif
#ifdef LINUX	
    pthread_mutex_destroy(&m_mutex);
#endif
    
#ifdef MUTEX_DEBUG_SIGNFILE
    MSNDEBUGSIGFILE((unsigned int )(void *)this, "mutex_block %s \n", name.c_str());
#endif
    
#ifdef BTDEBUG
    MSNDEBUG(DEBUG_MUTEX, "~mutex_block %s \n", name.c_str());
#endif
}

void mutex_block::lock()
{
    
#ifdef MUTEX_DEBUG_SIGNFILE
    MSNDEBUGSIGFILE((unsigned int )(void *)this, "wait for locked %s \n", name.c_str());
#endif
#ifdef BTDEBUG
    
#ifdef LINUX
    //MSNDEBUG(DEBUG_MUTEX, "%d wait for locked %s %d \n", ::pthread_self(),   name.c_str(), (unsigned int) this);
#endif
    
#ifdef WIN32
    MSNDEBUG(DEBUG_MUTEX, "%d wait for locked %s %d \n", ::GetCurrentThreadId(), name.c_str(), (unsigned int) this);
#endif
    
#endif
    
#ifdef WIN32
    ::EnterCriticalSection (&m_mutex);
#endif
    
#ifdef LINUX
    pthread_mutex_lock(&m_mutex);
#endif
    
    locks++;
    
    //assert(locks <= 1);
    
#ifdef MUTEX_DEBUG_SIGNFILE
    MSNDEBUGSIGFILE((unsigned int )(void *)this, "locked %s \n", name.c_str());
#endif
    
#ifdef BTDEBUG
    
#ifdef WIN32
    MSNDEBUG(DEBUG_MUTEX, "%d locked %s  %d \n", GetCurrentThreadId(), name.c_str(), (unsigned int) this);
#endif
    
#ifdef LINUX
    
    MSNDEBUG(DEBUG_MUTEX, "%d locked %s  %d \n", pthread_self(), name.c_str(), (unsigned int) this);

#endif
    
#endif
}

bool mutex_block::trylock()
{
    
#ifdef WIN32
    if (::TryEnterCriticalSection(&m_mutex))
    {   
        locks++;

        assert(locks <= 1);

        return true;
    }
    else
    {   
        return false;
    }
#endif
    
#ifdef LINUX
    pthread_mutex_lock(&m_mutex);
    ++locks;
    return true;
#endif
}

void mutex_block::unlock()
{
    
#ifdef MUTEX_DEBUG_SIGNFILE
    MSNDEBUGSIGFILE((unsigned int )(void *)this, "wait for unlocked %s \n", name.c_str());
#endif
    
#ifdef BTDEBUG
    
#ifdef WIN32
    MSNDEBUG(DEBUG_MUTEX, "%d  wait for unlocked %s  %d \n",GetCurrentThreadId(), name.c_str(), (unsigned int) this);
#endif
    
#ifdef LINUX
    MSNDEBUG(DEBUG_MUTEX, "%d  wait for unlocked %s  %d \n", pthread_self(), name.c_str(), (unsigned int) this);
#endif
    
#endif
    --locks;
    
#ifdef WIN32
    ::LeaveCriticalSection (&m_mutex);
#endif
    
#ifdef LINUX
    pthread_mutex_unlock(&m_mutex);
#endif
    
#ifdef MUTEX_DEBUG_SIGNFILE
    MSNDEBUGSIGFILE((unsigned int )(void *)this, "unlocked %s \n", name.c_str());
#endif
#ifdef BTDEBUG
    
#ifdef WIN32
    MSNDEBUG(DEBUG_MUTEX, "%d unlocked %s  %d \n", GetCurrentThreadId(), name.c_str(), (unsigned int) this);
#endif
    
#ifdef LINUX
    MSNDEBUG(DEBUG_MUTEX, "%d unlocked %s  %d \n", pthread_self(), name.c_str(), (unsigned int) this);
#endif
    
#endif
}

#undef BTDEBUG
void mutex_block::set_name(std::string n)
{
    this->name = n;
}

void mutex_block::wait_signt(cond_block * m, UINT32 t)
{
    
#ifdef MUTEX_DEBUG_SIGNFILE
    MSNDEBUGSIGFILE((unsigned int )(void *)this, "mutex_block wait for signt %s  %d seconds  \n", name.c_str(), t);
#endif
#ifdef BTDEBUG
    MSNDEBUG(DEBUG_MUTEX, "mutex_block wait for signt %s  %d seconds  \n", name.c_str(), t);
#endif	
    
#ifdef WIN32
    //��ʱ�󷵻أ� ��Ҫ�Լ��жϵ��׷������¼�û��
    unlock();
    ::ResetEvent (m->m_cond);
    //std::cout << "wait for single obj" << std::endl;
    ::WaitForSingleObject(m->m_cond, t*1000);
    //std::cout << "i got wait for" << std::endl;
    
#ifdef DEBUG_PRN    
    // std::cout << " i am WaitForSingleObject now" << (unsigned long)time(NULL) << std::endl;
#endif 
    
    lock();
#endif
    
#ifdef LINUX
    struct timespec timeout;
    timeout.tv_sec = time(NULL) + t;
    timeout.tv_nsec = 0;
    pthread_cond_timedwait(&(m->m_cond), &m_mutex, &timeout);
    
#endif
}

void mutex_block::board_signt(cond_block * m)
{
#ifdef MUTEX_DEBUG_SIGNFILE
    MSNDEBUGSIGFILE((unsigned int )(void *)this, "mutex_block board_signt %s\n", name.c_str());
#endif
#ifdef BTDEBUG
    MSNDEBUG(DEBUG_MUTEX, "mutex_block board_signt %s\n", name.c_str());
#endif 
    
#ifdef WIN32    
    ::SetEvent(m->m_cond);
    //::PulseEvent( m->m_cond);
    
#endif
#ifdef DEBUG_PRN    
    //std::cout << " i am setEvent now" << (unsigned long)time(NULL) << std::endl;
#endif 
    
#ifdef LINUX
    pthread_cond_broadcast(&(m->m_cond));
#endif
}

cond_block::cond_block(std::string n)
{
    
#ifdef WIN32
    m_cond = CreateEvent (NULL, TRUE, FALSE, NULL);
#endif
#ifdef LINUX
    pthread_cond_init(&m_cond, NULL);
#endif
    name = n;
    
#ifdef MUTEX_DEBUG_SIGNFILE
    MSNDEBUGSIGFILE((unsigned int )(void *)this, "create cond_block %s \n", name.c_str());
#endif
#ifdef BTDEBUG
    MSNDEBUG(DEBUG_MUTEX, "create cond_block %s \n", name.c_str());
#endif 
    
}

cond_block::~cond_block()
{
    
#ifdef MUTEX_DEBUG_SIGNFILE
    MSNDEBUGSIGFILE((unsigned int )(void *)this, "~cond_block %s\n", name.c_str());
#endif
#ifdef BTDEBUG
    MSNDEBUG(DEBUG_MUTEX, "~cond_block %s\n", name.c_str());
#endif 
    
#ifdef WIN32
    ::CloseHandle(m_cond);
#endif
    
#ifdef LINUX
    pthread_cond_destroy(&m_cond);
#endif
}

